package com.yuanli.card.manage.controller;

import com.github.pagehelper.PageInfo;
import com.yuanli.card.authentication.service.ISysUserService;
import com.yuanli.card.enumeration.CardOperateTypeEnum;
import com.yuanli.card.enumeration.CardPeriodEnum;
import com.yuanli.card.exception.ServiceException;
import com.yuanli.card.manage.service.*;
import com.yuanli.card.pojo.*;
import com.yuanli.card.req.*;
import com.yuanli.card.res.ResponseBean;
import com.yuanli.card.utils.ExcelTileFiledIndex;
import com.yuanli.card.utils.ExcelUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

@RestController
@RequestMapping("/card")
public class CardController {
    @Resource
    private CardService cardService;
    @Resource
    private ISysUserService sysUserService;
    @Resource
    private ComboService comboService;
    @Resource
    private ChannelService channelService;
    @Resource
    private PoolService poolService;
    @Resource
    private OutStoreService outStoreService;
    @Resource
    private ChannelInterfaceService channelInterfaceService;


    /*
        普通查询 卡板列表
     */
    @GetMapping("/query")
    public ResponseBean query(CardQueryReq req) throws Exception {
        Map<String, Object> data = new HashMap<>();
        if (req.getSaleStatus() == 0) {//库存
            req.setCardCustomerId(this.currentUserId());
        } else {
            if (req.getCardCustomerId() == null) {
                List<Integer> customerIds = sysUserService.getAllChildId();
                if (customerIds == null || customerIds.isEmpty()) {
                    data.put("total", 0);
                    data.put("list", Collections.emptyList());
                    return ResponseBean.success().setData(data);
                }
                req.setCardCustomerIds(customerIds);
            }
        }
        PageInfo<Card> pageInfo = cardService.query(req);
        data.put("total", pageInfo.getTotal());
        data.put("list", this.fillCard(pageInfo.getList(), req.getSaleStatus()));
        return ResponseBean.success().setData(data);
    }

    /*
        操作查询 批量操作 只能操作库存卡
     */
    @GetMapping("/operateQuery")
    public ResponseBean operateQuery(CardOperateQueryReq req) throws Exception {
        Map<String, Object> data = new HashMap<>();
        req.setCustomerId(this.currentUserId());
        PageInfo<Card> pageInfo = cardService.operateQuery(req);
        data.put("total", pageInfo.getTotal());
        data.put("list", this.fillCard(pageInfo.getList(), 0));
        return ResponseBean.success().setData(data);
    }

    /*
        导入查询 特殊操作
     */
    @PostMapping("/importQuery")
    public ResponseBean importQuery(CardOperateExportReq req) throws Exception {
        Map<String, Object> data = new HashMap<>();
        List<Card> cardList = this.excelToCardList(req.getFile());
        if (cardList == null || cardList.isEmpty()) {
            throw new ServiceException(1, "卡信息为空，请检查excel");
        }
        List<Card> resultList = cardService.importQuery(cardList, req);
        data.put("total", cardList.size());
        data.put("list", this.fillCard(resultList, 2));
        return ResponseBean.success().setData(data);
    }

    /*
        操作中查询 操作中和操作异常列表
     */
    @GetMapping("/operatingQuery")
    public ResponseBean operatingQuery(CardOperatingQueryReq req) throws Exception {
        if (req.getAll() == 1) {//当前用户
            req.setCustomerId(this.currentUserId());
        }
        PageInfo<Map<String,Object>> pageInfo = cardService.operatingQuery(req);
        Map<String, Object> data = new HashMap<>();
        data.put("total", pageInfo.getTotal());
        data.put("list", this.fillOperatingCard(pageInfo.getList()));
        return ResponseBean.success().setData(data);
    }

    @PostMapping("/enter")
    public ResponseBean enter(CardEnterReq req) {
        req.setCustomerId(this.currentUserId());
        cardService.enter(req);
        return ResponseBean.success();
    }

    //========================================================================批量操作

    @PostMapping("/sale")
    public ResponseBean sale(CardSaleReq req) {
        if (req.getCardOperateType() != CardOperateTypeEnum.sale) {
            throw new ServiceException(1, "参数错误");
        }
        req.setCustomerId(this.currentUserId());
        cardService.sale(req);
        return ResponseBean.success();
    }

    @PostMapping("/stop")
    public ResponseBean stop(CardOperateQueryReq req) {
        if (req.getCardOperateType() != CardOperateTypeEnum.stop) {
            throw new ServiceException(1, "参数错误");
        }
        req.setCustomerId(this.currentUserId());
        cardService.stop(req);
        return ResponseBean.success();
    }

    @PostMapping("/open")
    public ResponseBean open(CardOperateQueryReq req) {
        if (req.getCardOperateType() != CardOperateTypeEnum.open) {
            throw new ServiceException(1, "参数错误");
        }
        req.setCustomerId(this.currentUserId());
        cardService.open(req);
        return ResponseBean.success();
    }

    @PostMapping("/cancel")
    public ResponseBean cancel(CardOperateQueryReq req) {
        if (req.getCardOperateType() != CardOperateTypeEnum.cancel) {
            throw new ServiceException(1, "参数错误");
        }
        req.setCustomerId(this.currentUserId());
        cardService.cancel(req);
        return ResponseBean.success();
    }

    /*
    id连续且有序 不能修改excel
    同一套餐
     */
    @GetMapping("/export")
    public void export(CardOperateQueryReq req, HttpServletResponse response) throws IOException {
        if (req.getCardOperateType() != CardOperateTypeEnum.export) {
            throw new ServiceException(1, "参数错误");
        }
        req.setCustomerId(this.currentUserId());
        List<Card> cardList = cardService.export(req);
        if (cardList == null || cardList.isEmpty()) {
            throw new ServiceException(1, "导出的卡信息为空");
        }
        ExcelUtils.setResponseHeader(response, URLEncoder.encode("卡板信息.xls", "utf-8"));
        ExcelUtils.listToExcel(cardList, response.getOutputStream(), "Sheet1", this.cardFieldIndex());
    }

    //==================================================================================特殊操作

    /*
   销户
   月底处理
   先让运营商处理平台再处理
   id连续且有序
    */
    @PostMapping("/preclose")
    public ResponseBean preclose(CardOperateExportReq req) {
        List<Card> cardList = this.excelToCardList(req.getFile());
        if (cardList == null || cardList.isEmpty()) {
            throw new ServiceException(1, "卡信息为空，请检查excel");
        }
        cardService.preclose(cardList);
        return ResponseBean.success();
    }

    /*
      流量共享
      先让运营商处理平台再处理
      id连续且有序
   */
    @PostMapping("/flowShare")
    public ResponseBean flowShare(CardOperateExportReq req) {
        List<Card> cardList = this.excelToCardList(req.getFile());
        if (cardList == null || cardList.isEmpty()) {
            throw new ServiceException(1, "卡信息为空，请检查excel");
        }
        cardList.stream().forEach(cardParam -> {
            if (StringUtils.isNotBlank(cardParam.getPoolCode())) {
                throw new ServiceException("卡中存在已流量共享的卡,请检查后操作");
            }
        });
        cardService.flowShare(cardList);
        return ResponseBean.success();
    }

    private List<Map<String, Object>> fillCard(List<Card> list, Integer type) throws Exception {
        if (list == null || list.isEmpty()) {
            return null;
        }
        List<String> iccids = list.stream().map(Card::getIccid).collect(Collectors.toList());
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        Future<Map<String, CardPeriodEnum>> periodFuture = executorService.submit(() -> {
            return channelInterfaceService.batchQueryCardLifeCycle(iccids,null);
        });
        Future<Map<String, Integer>> gprsFuture = executorService.submit(() -> {
            return channelInterfaceService.batchQueryGprsStatus(iccids);
        });
        Future<Map<String, CardFlow>> flowFuture = executorService.submit(() -> {
            return channelInterfaceService.batchQueryRealtimeGprsInfo(iccids);
        });
        Map<String, CardPeriodEnum> periodMap = periodFuture.get();
        Map<String, Integer> gprsMap = gprsFuture.get();
        Map<String, CardFlow> flowMap = flowFuture.get();
        executorService.shutdown();

        int userId = sysUserService.currentUser().getId().intValue();
        List<Map<String, Object>> result = list.parallelStream().map(card -> {
            Map<String, Object> map = new HashMap<>();
            map.put("id", card.getId());
            map.put("iccid", card.getIccid());
            Pool pool = poolService.getByPoolCode(card.getPoolCode());
            map.put("poolName", pool == null ? null : pool.getPoolName());
            Channel channel = channelService.findChannelByNo(card.getChannelCode());
            map.put("channelName", channel == null ? null : channel.getName());
            Combo combo = comboService.getByComboNo(card.getComboCode());
            map.put("comboName", combo == null ? null : combo.getComboName());
            Integer customerId = null;
            if (type == 1) {//显示出售客户
                OutStore outStore = outStoreService.getByCardId(card.getId(), userId);
                if (outStore != null) {
                    customerId = outStore.getSaleCustomerId();
                }
            } else if (type == 2) {//显示卡所属客户
                customerId = card.getCustomerId();
            }
            if (customerId != null) {
                SysUser user = sysUserService.findById(customerId.longValue());
                map.put("customerName", user == null ? null : user.getNickname());
            }
            CardFlow cardFlow = flowMap.get(card.getIccid());
            if (cardFlow != null) {
                map.put("used", cardFlow.getUsed() + "M");
                map.put("left", cardFlow.getLeft() + "M");
                map.put("total", cardFlow.getTotal() + "M");
            }
            if (periodMap.get(card.getIccid()) == null) {
                map.put("period", card.getPeriod());
            }else{
                map.put("period", periodMap.get(card.getIccid()).name());
            }
            map.put("gprs", gprsMap.get(card.getIccid()));

            map.put("closeStatus", card.getCloseStatus());
            map.put("createTime", card.getCreateTime());
            map.put("enterTime", card.getEnterTime());
            return map;
        }).collect(Collectors.toList());
        return result;
    }

    private List<Map<String, Object>> fillOperatingCard(List<Map<String,Object>> list) throws Exception {
        if (list == null || list.isEmpty()) {
            return null;
        }
        List<Map<String, Object>> result = list.parallelStream().map(map -> {
            Channel channel = channelService.findChannelByNo(map.get("channelCode").toString());
            map.put("channelName", channel == null ? null : channel.getName());
            Combo combo = comboService.getByComboNo(map.get("comboCode").toString());
            map.put("comboName", combo == null ? null : combo.getComboName());
            SysUser user = sysUserService.findById(Long.valueOf(map.get("customerId").toString()));
            map.put("customerName", user == null ? null : user.getNickname());
            return map;
        }).collect(Collectors.toList());
        return result;
    }

    private List<Card> excelToCardList(MultipartFile file) {
        List<Card> result = null;
        try {
            result = ExcelUtils.excelToList(file.getInputStream(), 0, this.cardFieldIndex(), Card.class);
        } catch (IOException e) {
            throw new ServiceException("解析excel异常");
        }
        return result;
    }

    private ExcelTileFiledIndex cardFieldIndex() {
        ExcelTileFiledIndex filedIndex = new ExcelTileFiledIndex();
        filedIndex.addByAutoIndex("id", "id");
        filedIndex.addByAutoIndex("iccid", "iccid");
        return filedIndex;
    }

    private Integer currentUserId() {
        return sysUserService.currentUser().getId().intValue();
    }
}
